package vroom.optimization.online.jmsa.benchmarking; import java.awt.Dimension; import java.awt.Font; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.plaf.FontUIResource; import org.apache.log4j.FileAppender; import org.apache.log4j.Layout; import org.apache.log4j.Level; import org.apache.log4j.PatternLayout; import org.apache.log4j.lf5.LF5Appender; import umontreal.iro.lecuyer.rng.MRG32k3a; import umontreal.iro.lecuyer.rng.RandomStream; import vroom.common.heuristics.GenericNeighborhood; import vroom.common.heuristics.NeighborhoodBase; import vroom.common.heuristics.cw.CWLogging; import vroom.common.heuristics.vls.VLSLogging; import vroom.common.heuristics.vns.VariableNeighborhoodSearch; import vroom.common.modeling.dataModel.DynamicInstance; import vroom.common.modeling.dataModel.Request; import vroom.common.modeling.io.NovoaPersistenceHelper; import vroom.common.modeling.io.NovoaPersistenceHelper.DemandDistribution; import vroom.common.utilities.ExtendedReentrantLock; import vroom.common.utilities.Stopwatch; import vroom.common.utilities.callbacks.CallbackStack; import vroom.common.utilities.dataModel.ObjectWithIdComparator; import vroom.common.utilities.logging.LoggerHelper; import vroom.common.utilities.logging.Logging; import vroom.common.utilities.logging.UnlimitedAsyncAppender; import vroom.common.utilities.ssj.RandomGeneratorManager; import vroom.optimization.online.jmsa.IActualRequest; import vroom.optimization.online.jmsa.IDistinguishedSolution; import vroom.optimization.online.jmsa.MSABase; import vroom.optimization.online.jmsa.MSAGlobalParameters; import vroom.optimization.online.jmsa.MSASequential; import vroom.optimization.online.jmsa.events.MSACallbackBase; import vroom.optimization.online.jmsa.events.MSACallbackEvent; import vroom.optimization.online.jmsa.events.MSACallbackEvent.EventTypes; import vroom.optimization.online.jmsa.events.ResourceEvent; import vroom.optimization.online.jmsa.utils.MSALogging; import vroom.optimization.online.jmsa.vrp.MSAVRPInstance; import vroom.optimization.online.jmsa.vrp.VRPActualRequest; import vroom.optimization.online.jmsa.vrp.VRPParameterKeys; import vroom.optimization.online.jmsa.vrp.VRPPoolCleanerBase; import vroom.optimization.online.jmsa.vrp.VRPRequestSamplerBase; import vroom.optimization.online.jmsa.vrp.VRPRequestValidatorBase; import vroom.optimization.online.jmsa.vrp.VRPScenario; import vroom.optimization.online.jmsa.vrp.visu.MSAVisualizationFrame; import vroom.optimization.online.jmsa.vrp.vrpsd.VRPSDActualRequest; import vroom.optimization.online.jmsa.vrp.vrpsd.VRPSDConsensus; import vroom.optimization.online.jmsa.vrp.vrpsd.VRPSDResourceHandler; import vroom.optimization.online.jmsa.vrp.vrpsd.VRPSDSVScenarioOptimizer; import vroom.optimization.online.jmsa.vrp.vrpsd.VRPSDScenarioGenerator; import vroom.optimization.online.jmsa.vrp.vrpsd.VRPSDScenarioUpdater; /** * <code>NovoaRun</code> is a class used to run an MSA procedure on a simulation of a Novoa instance * <p> * Creation date: May 11, 2010 - 11:26:27 AM * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp">SLP</a> * @version 2.0 */ public class NovoaRun implements Runnable { public static class NovoaRunThread extends Thread { private MSABase<?, ?> mMSA; private ReturnStatus mStatus; private String mMessage; private final ReentrantLock mLock = new ReentrantLock(); private final Condition mStatusCondition = mLock.newCondition(); public Condition getStatusCondition() { return mStatusCondition; } public void setMSA(MSABase<?, ?> mSA) { mMSA = mSA; } public ReturnStatus getStatus() { return mStatus; } private void setStatus(ReturnStatus status) { mLock.lock(); mStatus = status; mStatusCondition.signalAll(); mLock.unlock(); } public NovoaRunThread(ThreadGroup group, Runnable target, String name) { super(group, target, name); mMessage = "na"; setStatus(ReturnStatus.UNKNOWN); } @Override public void run() { try { setStatus(ReturnStatus.RUNNING); super.run(); mMessage = "ok"; setStatus(ReturnStatus.NORMAL); } catch (Exception e) { mMessage = e.getClass().getSimpleName(); setStatus(ReturnStatus.EXCEPTION); mMSA.stop(); LOGGER.exception("NovoaRunThread.run MSA:%s", e, mMSA); } catch (OutOfMemoryError e) { mMSA.stop(); mMSA.getProxy().getScenarioPool().clear(); System.gc(); mMessage = e.getClass().getSimpleName(); setStatus(ReturnStatus.EXCEPTION); e.printStackTrace(); } } public String getMessage() { return mMessage; } } public static class NovoaRunThreadFactory implements ThreadFactory { private static int sThreadId = 0; @Override public NovoaRunThread newThread(Runnable r) { sThreadId++; NovoaRunThread t = new NovoaRunThread(Thread.currentThread().getThreadGroup(), r, String.format("NovoaRun-%s", sThreadId)); t.setMSA((MSABase<?, ?>) r); return t; } } protected static final NovoaRunThreadFactory sThreadFactory = new NovoaRunThreadFactory(); /** * <code>ServiceSimulationCallback</code> is a callback that will be associated to * {@linkplain EventTypes#MSA_NEW_DISTINGUISHED_SOLUTION new distinguished mSolution} events and will simulate the * servicing of a request * <p> * Creation date: 3 mai 2010 - 16:02:03 * * @author Victor Pillac, <a href="http://uniandes.edu.co">Universidad de Los Andes</a>-<a * href="http://copa.uniandes.edu.co">Copa</a> <a href="http://www.emn.fr">Ecole des Mines de Nantes</a>-<a * href="http://www.irccyn.ec-nantes.fr/irccyn/d/en/equipes/Slp" >SLP</a> * @version 1.0 */ private class ServiceSimulationCallback extends MSACallbackBase { private ServiceSimulationCallback() { } /* * (non-Javadoc) * @see vroom.optimization.online.jmsa.events.MSACallbackBase#execute(edu .uniandes * .copa.jMSA.events.MSACallbackEvent, java.lang.Object[]) */ @Override public synchronized void execute(MSACallbackEvent event) { switch (event.getType()) { case MSA_NEW_DISTINGUISHED_SOLUTION: if (event.getParams()[1] != null && !mSimulation.isBusy()) { mSimulation.setSolution((IDistinguishedSolution) event.getParams()[1]); } break; case EVENTS_RESOURCE: ResourceEvent resEv = (ResourceEvent) event.getParams()[0]; switch (resEv.getType()) { case STOP: info("Resource STOP detected, ending the MSA procedure"); stop(); break; default: // DO NOTHING break; } break; case MSA_END: } } @Override public int getPriority() { return 0; } @Override public boolean isExecutedSynchronously() { return false; } } private class ServiceSimulationRunnable implements Runnable { private boolean mRunning = true; private IDistinguishedSolution mSolution; public boolean isBusy() { return mSolution != null; } @Override public void run() { Object lock = new Object(); mRunning = true; synchronized (lock) { while (mRunning) { while (mRunning && mSolution == null) { try { lock.wait(200); } catch (InterruptedException e) { exception("Exception caught in simulation thread", e); } } if (mSolution != null) { simulateService(); mSolution = null; } } } } protected synchronized void setSolution(IDistinguishedSolution solution) { mSolution = solution; } private synchronized void simulateService() { info("New distinguished mSolution: " + mSolution); info(" Pending requets: " + mInstance.getPendingRequests().size()); for (int resource = 0; resource < mInstance.getFleet().size(); resource++) { VRPActualRequest currentReq = (VRPActualRequest) mSolution.getNextRequest(resource); if ((currentReq == null || currentReq.isDepot()) && mInstance.getPendingRequests().isEmpty()) { info("Resource has finished servicing all requests"); mMSA.getEventFactory().raiseResourceStop(resource, currentReq); } else if (currentReq != null) { info("Enforce decision: " + currentReq); mMSA.getEventFactory().raiseRequestAssignedEvent(resource, currentReq); VRPActualRequest lastReq = mInstance.getLastAssignedRequest(0); int travelTime = lastReq != null ? (int) Math.ceil((mInstance.getCostDelegate() .getDistance(lastReq, currentReq) * mTravelInvertSpeed)) : 1; info("Simulating travel time"); waitSec(travelTime); double d[] = null; if (currentReq instanceof VRPSDActualRequest) { final double[] dem = new double[] { mDemands.get(currentReq) }; d = dem; info("Start of service event: %s actual demands: %s", currentReq, Arrays.toString(dem)); } else { info("Start of service event: " + currentReq); } mMSA.getEventFactory().raiseStartOfServiceEvent(resource, currentReq, d); info("Simulating service time"); waitSec(SERVICE_TIME); info("End of service event: " + currentReq); mMSA.getEventFactory().raiseEndOfServiceEvent(resource, currentReq); } } } public void stop() { mRunning = false; } } /** A return status for the run */ public static enum ReturnStatus { NORMAL, TIME_LIMIT, EXCEPTION, RUNNING, UNKNOWN }; public static String INSTANCE_DIRECTORY = "../Instances/vrpsd/novoa/"; /** Instance name format string: [S]i_[n]r[nodeJ].dat */ public static final String INSTANCE_FORMAT = "%si_%sr%s.dat"; public static final String LOG_FILE_FORMAT_STRING = "log/%1$ty%1$tm%1$td_%1$tk-%1$tM_run_log.log"; public static Layout LOG_FILE_LAYOUT = new PatternLayout( "%c %-30d{HH:mm:ss} %-5p%n [%-10t] : %m%n"); protected static final LoggerHelper LOGGER = LoggerHelper .getLogger("NovoaBenchmark"); public static int SERVICE_TIME = 5; // 0 i_20r1c91 (easy?) // static int sCap = 91; // static int sRep = 1; // static int sSet = 1; // static int sSize = 20; // static int sRun = 0; // 0 i_30r1c137 (easy) static int sCap = 137; static int sRep = 1; static int sSet = 1; static int sSize = 30; static int sRun = 0; // run 38 i_30r2c87 (hard) // static int sCap = 87; // static int sRep = 2; // static int sSet = 1; // static int sSize = 30; // static int sRun = 38; // run 1 i_40r1c116 // static int sCap = 116; // static int sRep = 1; // static int sSet = 1; // static int sSize = 40; // static int sRun = 1; // 94 i_40r1c116 // static int sCap = 116; // static int sRep = 1; // static int sSet = 1; // static int sSize = 40; // static int sRun = 94; // run set size rep cap // 46 1 40 1 116 // static int sCap = 116; // static int sRep = 1; // static int sSet = 1; // static int sSize = 40; // static int sRun = 46; // static int sCap = 9; // static int sRep = 3; // static int sSet = 1; // static int sSize = 5; // static int sRun = 25; // 28 i_40r3c116 (hard?) // static int sCap = 116; // static int sRep = 3; // static int sSet = 1; // static int sSize = 40; // static int sRun = 28; // 12 i_40r5c183 (hard) // static int sCap = 183; // static int sRep = 5; // static int sSet = 1; // static int sSize = 40; // static int sRun = 12; public static int TRAVEL_TIME = 5; /** * log an error message when an exception is caught * * @param context * @param e * @param args */ public void exception(String context, Exception e, Object... args) { Object[] argst = new Object[args.length + 4]; argst[0] = getMsa() != null && getMsa().getInstance() != null ? getMsa().getInstance() .getName() : "na"; argst[1] = mRunId; argst[2] = e.getClass().getSimpleName(); argst[3] = e.getMessage(); for (int i = 4; i < argst.length; i++) { argst[i] = args[i - 4]; } LOGGER.error("NovoaRun[%s-%s] > Exception caught in " + context + " %s: %s", e, argst); } /** * log an error message when an exception is caught * * @param context * @param e * @param args */ public void error(String message, Object... args) { Object[] argst = new Object[args.length + 2]; argst[0] = getMsa() != null && getMsa().getInstance() != null ? getMsa().getInstance() .getName() : "na"; argst[1] = mRunId; for (int i = 3; i < argst.length; i++) { argst[i] = args[i - 3]; } LOGGER.error("NovoaRun[%s-%s] > " + message, argst); } /** * Log an info message * * @param message */ public void info(String message, Object... args) { Object[] argst = new Object[args.length + 2]; argst[0] = getMsa() != null && getMsa().getInstance() != null ? getMsa().getInstance() .getName() : "na"; argst[1] = mRunId; for (int i = 2; i < argst.length; i++) { argst[i] = args[i - 2]; } LOGGER.info("NovoaRun[%s-%s] > " + message, argst); } /** * Load default parameters for the MSA procedure * * @param params */ public static void loadDefaultParameters(MSAGlobalParameters params) { VRPParameterKeys.registerRequiredParameters(); params.resetDefaultValues(); params.set(MSAGlobalParameters.POOL_CLEANER_CLASS, VRPPoolCleanerBase.class); params.set(MSAGlobalParameters.REQUEST_VALIDATOR_CLASS, VRPRequestValidatorBase.class); params.set(MSAGlobalParameters.REQUEST_SAMPLER_CLASS, VRPRequestSamplerBase.class); params.set(MSAGlobalParameters.POOL_SIZE, 50); params.set(MSAGlobalParameters.POOL_INITIAL_PROPORTION, 0.7); params.set(MSAGlobalParameters.SCENARIO_GENERATOR_CLASS, VRPSDScenarioGenerator.class); params.set(VRPParameterKeys.ACTUAL_REQUEST_CLASS, VRPSDActualRequest.class); params.set(MSAGlobalParameters.SCENARIO_OPTIMIZER_CLASS, VRPSDSVScenarioOptimizer.class); params.set(MSAGlobalParameters.SCENARIO_UPDATER_CLASS, VRPSDScenarioUpdater.class); params.set(MSAGlobalParameters.SOLUTION_BUILDER_CLASS, VRPSDConsensus.class); params.set(MSAGlobalParameters.RANDOM_SEED, 0l); } /** * Main method that run a test * * @param args * set instanceSize replica capacity */ public static void main(String[] args) { NeighborhoodBase.setCheckSolutionAfterMove(false); GenericNeighborhood.setCheckSolutionAfterMove(false); setupFonts(24); setupLoggers(LoggerHelper.LEVEL_DEBUG, LoggerHelper.LEVEL_DEBUG, false, false, true); LOGGER.setLevel(LoggerHelper.LEVEL_DEBUG); VariableNeighborhoodSearch.LOGGER.setLevel(LoggerHelper.LEVEL_WARN); ExtendedReentrantLock.LOGGER.setLevel(LoggerHelper.LEVEL_LOW_DEBUG); PerfectInformationSolver pisolver = new PerfectInformationSolver(); // VLSLogging.getBaseLogger().setLevel(LoggerHelper.LEVEL_LOW_DEBUG); // CWLogging.getBaseLogger().setLevel(LoggerHelper.LEVEL_INFO); int run = sRun; int set = sSet; int size = sSize; int rep = sRep; int cap = NovoaPersistenceHelper.getCapacityIdx(size, set, sCap); // DemandDistribution demDist = DemandDistribution.NORMAL; DemandDistribution demDist = DemandDistribution.UNIFORM; if (args.length == 4) { try { set = Integer.valueOf(args[0]); size = Integer.valueOf(args[1]); rep = Integer.valueOf(args[2]); cap = Integer.valueOf(args[3]); } catch (Exception e) { System.out.println(e.getMessage()); System.out.println("Arguments: set instanceSize replica capacity"); System.exit(1); } } else { System.out.println("Arguments: set instanceSize replica capacity"); } MSAGlobalParameters params = new MSAGlobalParameters(); loadDefaultParameters(params); params.set(MSAGlobalParameters.MAX_THREADS, Runtime.getRuntime().availableProcessors() - 2); params.set(MSAGlobalParameters.MIN_THREADS, Runtime.getRuntime().availableProcessors() - 2); // params.set(MSAGlobalParameters.MAX_THREADS, 1); // params.set(MSAGlobalParameters.MIN_THREADS, 1); params.set(MSAGlobalParameters.SOLUTION_BUILDER_CLASS, VRPSDConsensus.class); // params.set(MSAGlobalParameters.SOLUTION_BUILDER_CLASS, VRPSDDetourRegret.class); // params.set(MSAGlobalParameters.SOLUTION_BUILDER_CLASS, VRPSDSmartConsensus.class); // params.set(MSAGlobalParameters.SOLUTION_BUILDER_CLASS, // VRPSDSampledRegret.class); // params.set(MSAGlobalParameters.POOL_SIZE, 10); NovoaRun novoa = null; try { novoa = new NovoaRun(set, size, rep, cap, run, params, demDist); } catch (IOException e) { LOGGER.exception("NovoaRun.main", e); System.exit(1); } // Visualization MSAVisualizationFrame frame = new MSAVisualizationFrame(novoa.mMSA, pisolver.solvePerfectInformation(run, size, rep, cap, set, Integer.MAX_VALUE, false, true, demDist)); frame.pack(); frame.setSize(new Dimension(1200, 700)); frame.setVisible(true); // novoa.setTravelInvertSpeed(5); novoa.setTimeLimit(30); novoa.run(); Object o = new Object(); synchronized (o) { try { o.wait(10 * 1000); } catch (InterruptedException e) { } } CallbackStack.stopAllThreads(); System.out.println(novoa.getStatus()); novoa = null; // frame.detach(); Runtime.getRuntime().gc(); } private static void setupFonts(float size) { // UIManager.put("TextField.font", new FontUIResource("Arial", Font.PLAIN, 17)); UIDefaults defaults = UIManager.getDefaults(); Enumeration<?> keys = defaults.keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); Object value = defaults.get(key); if (value != null && value instanceof Font) { UIManager.put(key, null); Font font = UIManager.getFont(key); if (font != null) { UIManager.put(key, new FontUIResource(font.deriveFont(size))); } System.out.println(key); } } } /** * Setup the main loggers for the novoa run * * @param msaLoggerLevel * {@link Level} for the MSA logger * @param rootLoggerLevel * {@link Level} for the root logger * @param addSwingAppender * <code>true</code> if a swing appender should be added * @param addFileAppender * <code>true</code> if a default file appender should be added * @param async * <code>true</code> if appending should be done in an asynchronous way (recomended) */ public static void setupLoggers(Level msaLoggerLevel, Level rootLoggerLevel, boolean addSwingAppender, boolean addFileAppender, boolean async) { Level min = msaLoggerLevel; if (msaLoggerLevel.isGreaterOrEqual(rootLoggerLevel)) { min = rootLoggerLevel; } Logging.setupRootLogger(min, LoggerHelper.LEVEL_LOW_DEBUG, async); // Configuring loggers // MSA Logging.setLoggerLevel(MSALogging.BASE_LOGGER, msaLoggerLevel); // CW Logging.setLoggerLevel(CWLogging.BASE_LOGGER, LoggerHelper.LEVEL_WARN); // VLS Logging.setLoggerLevel(VLSLogging.BASE_LOGGER, LoggerHelper.LEVEL_WARN); // Test LOGGER.setLevel(msaLoggerLevel); if (addSwingAppender || addFileAppender) { UnlimitedAsyncAppender appender = new UnlimitedAsyncAppender(); appender.setBufferSize(2048); if (addSwingAppender) { LF5Appender swingAppender = new LF5Appender(); appender.addAppender(swingAppender); } if (addFileAppender) { try { FileAppender fileAppender = new FileAppender(LOG_FILE_LAYOUT, String.format( LOG_FILE_FORMAT_STRING, new Date(System.currentTimeMillis())), true); appender.addAppender(fileAppender); } catch (IOException e) { e.printStackTrace(); } } MSALogging.getBaseLogger().addAppender(appender); CWLogging.getBaseLogger().addAppender(appender); VLSLogging.getBaseLogger().addAppender(appender); } } /** * Pause the current thread for the given time * * @param sec */ void waitSec(int sec) { info("Waiting " + sec + "s"); try { Thread.sleep(sec * 1000); } catch (InterruptedException e) { exception("Exception caught while waiting", e); } } private final Map<VRPActualRequest, Double> mDemands; private final MSAGlobalParameters mGlobalParams; private final MSAVRPInstance mInstance; private final MSABase<VRPScenario, MSAVRPInstance> mMSA; private final RandomGeneratorManager mRNDGenManager; private final RandomStream mRNDStream; private final DynamicInstance mSimInstance; private final ServiceSimulationRunnable mSimulation; private double mTravelInvertSpeed = 40; private ReturnStatus mReturnStatus; private int mTimeLimit; private final int mRunId; private NovoaRunThread mMsaThread; /** * Creates a new <code>NovoaRunningTest</code> * * @param set * the instance set (1 or 2) * @param size * the instance size (5,8,20,30,40,60,100,150) * @param num * the instance number (1 to 5) * @param cap * the vehicle capacity (0 or 1) * @param runId * @throws IOException * if the instance could not be read * @see NovoaPersistenceHelper#readInstance(int, int, int, int, Long) */ public NovoaRun(int set, int size, int num, int cap, int runId, MSAGlobalParameters params, DemandDistribution dist) throws IOException { mRunId = runId; long[] seeds = NovoaBenchmarking.getSeeds(runId, size, num, cap, set); // 2 hours time limit setTimeLimit(60 * 2); // Read instance // ---------------------------------------------------------------------- if (params != null) { mGlobalParams = params; } else { mGlobalParams = new MSAGlobalParameters(); loadDefaultParameters(mGlobalParams); } // Read instance // ---------------------------------------------------------------------- NovoaPersistenceHelper instanceLoader = new NovoaPersistenceHelper(); instanceLoader.setDemandDistribution(dist); mInstance = new MSAVRPInstance(instanceLoader.readInstance(size, set, num, cap, null), mGlobalParams); // ---------------------------------------------------------------------- info(""); info("----------------------------------------"); info("Loaded instance:"); info("----------------------------------------"); info(" Name: " + mInstance.getName()); info(" Size: " + mInstance.getRequestCount()); info(" Vehicle Capacity: " + mInstance.getFleet().getVehicle(0).getCapacity()); info(" Seeds: " + Arrays.toString(seeds)); // Random number generators // ---------------------------------------------------------------------- MRG32k3a.setPackageSeed(seeds); mRNDStream = new MRG32k3a("SimulationStream"); ((MRG32k3a) mRNDStream).setSeed(seeds); mRNDGenManager = new RandomGeneratorManager(); mRNDGenManager.setRandomStream(mRNDStream); // ---------------------------------------------------------------------- // Sample demands // ---------------------------------------------------------------------- mDemands = NovoaSimulationDemands.getDemands(seeds, mInstance); List<VRPActualRequest> pendingRequests = mInstance.getPendingRequests(); Collections.sort(pendingRequests, new ObjectWithIdComparator()); for (VRPActualRequest req : pendingRequests) { info(" \t%s -> d=%s", req, mDemands.get(req)); } // ---------------------------------------------------------------------- // Seeds for the MSA procedure long[] seedsL = new long[seeds.length]; for (int i = 0; i < seedsL.length; i++) { seedsL[i] = (long) Math.floor(mRNDStream.nextDouble() * 4294944443l); } mGlobalParams.set(MSAGlobalParameters.POOL_SIZE, Math.min(size * 10, 100)); mGlobalParams.set(MSAGlobalParameters.RANDOM_SEEDS, seedsL); // ---------------------------------------------------------------------- // Create the simulation instance // ---------------------------------------------------------------------- mSimInstance = new DynamicInstance(getInstance().getName(), getInstance().getID(), getInstance().getRoutingProblem()); mSimInstance.setFleet(getInstance().getFleet()); mSimInstance.setDepots(Collections.singletonList(getInstance().getDepot(0))); mSimInstance.setCostHelper(getInstance().getCostDelegate()); for (Entry<VRPActualRequest, Double> entry : mDemands.entrySet()) { // Create a copy of the request Request r = new Request(entry.getKey().getID(), entry.getKey().getNode()); r.setDemands(entry.getValue()); mSimInstance.addRequest(r); } // ---------------------------------------------------------------------- // Auto adjust travel speed for faster simulations // ---------------------------------------------------------------------- mTravelInvertSpeed = Math.max(3, size / 10); info(" Travel speed: %ss/unit", mTravelInvertSpeed); info("----------------------------------------"); // ---------------------------------------------------------------------- // Initialize the MSA procedure // ---------------------------------------------------------------------- mMSA = new MSASequential<VRPScenario, MSAVRPInstance>(mInstance, mGlobalParams); mMSA.setEventHanlder(ResourceEvent.class, new VRPSDResourceHandler(mMSA.getProxy())); mSimulation = new ServiceSimulationRunnable(); try { mMSA.registerCallback(EventTypes.MSA_NEW_DISTINGUISHED_SOLUTION, new ServiceSimulationCallback()); mMSA.registerCallback(EventTypes.EVENTS_RESOURCE, new ServiceSimulationCallback()); mMSA.registerCallback(EventTypes.MSA_NEW_DISTINGUISHED_SOLUTION, new DistinguishedSolutionCallback("solutions.out")); mMSA.registerCallback(EventTypes.EVENTS_RESOURCE, new ResourceCallback( "resources_log.out")); } catch (IOException e) { MSALogging.getBaseLogger().warn( "Exception caught in method MSARunningTest.MSARunningTest", e); } // ---------------------------------------------------------------------- } /** * @return a string describing the client sampled demands */ public String getDemands() { StringBuffer s = new StringBuffer(mDemands.size() * 5); List<Entry<VRPActualRequest, Double>> dems = new ArrayList<Entry<VRPActualRequest, Double>>( mDemands.entrySet()); Collections.sort(dems, new Comparator<Entry<VRPActualRequest, Double>>() { @Override public int compare(Entry<VRPActualRequest, Double> o1, Entry<VRPActualRequest, Double> o2) { return o1.getKey().getID() - o2.getKey().getID(); } }); for (Entry<VRPActualRequest, Double> e : dems) { s.append(String.format("[%s:%s] ", e.getKey().getID(), e.getValue())); } return s.toString(); } /** * Getter for the MSA instance, requests do not contain the realization of the demand. * * @return the instance being used by the MSA procedure */ public MSAVRPInstance getInstance() { return mInstance; } /** * Getter for the {@link MSABase} instance * * @return the msa */ public MSABase<VRPScenario, MSAVRPInstance> getMsa() { return mMSA; } /** * Getter for the simulation instance, which contains the realization of the demands. * * @return an instance with the demand realizations */ public DynamicInstance getSimulationInstance() { return mSimInstance; } public double getTravelInvertSpeed() { return mTravelInvertSpeed; } /** * Getter for <code>timeLimit</code> * * @return the timeLimit */ public int getTimeLimit() { return mTimeLimit; } /** * Setter for time limit * * @param timeLimit * the time limit to set in minutes */ public void setTimeLimit(int timeLimit) { mTimeLimit = timeLimit; } /** * Getter for <code>returnStatus</code> * * @return the returnStatus */ public ReturnStatus getStatus() { return mReturnStatus; } /** * Return status string * * @return a string describing the return status string */ public String getStatusString() { return String.format("%s[%s]", getStatus(), mMsaThread == null ? "null" : mMsaThread.getMessage()); } /** * Log the state of the MSA */ private void printState() { info("Final state of the MSA procedure: %s", mMSA); info(""); info("----------------------------------------"); info("Served requests:"); for (IActualRequest r : mInstance.getServedRequests()) { info(" %s", r); } info("----------------------------------------"); info("Pending requests:"); for (IActualRequest r : mInstance.getPendingRequests()) { info(" %s", r); } info("----------------------------------------"); info(""); info("----------------------------------------"); info("Solution:"); info(mMSA.getCurrentSolution().toString()); info("----------------------------------------"); } /** * Start the MSA procedure */ @Override public void run() { mReturnStatus = ReturnStatus.RUNNING; Thread simThread = new Thread(mSimulation, "SimThread"); simThread.setDaemon(true); simThread.start(); Stopwatch timer = new Stopwatch(getTimeLimit() * 60000l); timer.start(); info(""); info("Starting the MSA"); mMsaThread = sThreadFactory.newThread(mMSA); mMsaThread.start(); info(""); info("Waiting for the MSA to initialize"); while (!mMSA.isInitialized()) { mMSA.acquireLock(); try { mMSA.getInitializedCondition().await(); } catch (InterruptedException e) { mReturnStatus = ReturnStatus.EXCEPTION; exception("NovoaRun.run while waiting for initialization", e); mMSA.stop(); break; } mMSA.releaseLock(); } info("Raising resource start event"); mMSA.getEventFactory().raiseResourceStart(0, mInstance.getDepotsVisits().iterator().next()); waitSec(1); info("Raising decision event"); mMSA.getEventFactory().raiseDecisionEvent(); // The rest of the simulation will be done in the // SimulationCallback info("Waiting for the MSA to finish"); while (mMSA.isRunning() && mMsaThread.getStatus() == ReturnStatus.RUNNING) { try { mMsaThread.mLock.lock(); mMsaThread.getStatusCondition().await(5, TimeUnit.SECONDS); mMsaThread.mLock.unlock(); if (timer.hasTimedOut()) { error("NovoaRun.run Time limit reached: %s", timer); mMSA.stop(); mReturnStatus = ReturnStatus.TIME_LIMIT; break; } } catch (InterruptedException e) { LOGGER.exception("NovoaRun.run", e); mReturnStatus = ReturnStatus.EXCEPTION; stop(); break; } } if (mReturnStatus == ReturnStatus.RUNNING) { mReturnStatus = mMsaThread.getStatus(); } // while (mMSA.isRunning()) { // mMSA.acquireLock(); // try { // mMSA.getRunningCondition().await(1, TimeUnit.SECONDS); // } catch (InterruptedException e) { // exception("NovoaRun.run while waiting for initialization", e); // mReturnStatus = ReturnStatus.EXCEPTION; // stop(); // break; // } // mMSA.releaseLock(); // if (timer.hasTimedOut()) { // error("NovoaRun.run Time limit reached: %s", timer); // mMSA.stop(); // mReturnStatus = ReturnStatus.TIME_LIMIT; // if (mExceptionSafe) { // mMSAExecutor.shutdownNow(); // } else { // // Nothing can be done // } // break; // } // } printState(); mSimulation.stop(); } public void setTravelInvertSpeed(double speed) { mTravelInvertSpeed = speed; } /** * Stop the MSA procedure */ private void stop() { mMSA.stop(); mSimulation.stop(); } }